package smcms.service.sso.config;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.util.ObjectUtils;
import smcms.commons.api.entity.result.CommonsResult;
import smcms.commons.api.entity.util.JwtUtil;
import smcms.service.sso.entity.AccountReq;
import smcms.service.sso.entity.AccountResp;
import smcms.service.sso.mapper.AccountMapper;
import smcms.service.sso.service.impl.UserDetailService;

import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CommonsResult commonsResult;
    @Autowired
    private UserDetailService userDetailService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private JwtUtil jwt;
    @Autowired
    private AccountMapper accountMapper;
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.cors();
        http.csrf().disable();
                // 登录成功
        http
                .authorizeRequests().antMatchers("/**").permitAll().and()
                .formLogin()
                .loginProcessingUrl("/login")
                .passwordParameter("password")
                .usernameParameter("username")
                .successHandler((httpServletRequest, httpServletResponse, authentication) -> {

                    HashMap<String, Object> map = new HashMap<>();
                    AccountResp principal = (AccountResp)authentication.getPrincipal();
                    map.put("username",principal.getUsername());
                    map.put("cloudId",principal.getCloudId());
                    map.put("staffName",principal.getStaffName());
                    String token = null;
                    if (ObjectUtils.isEmpty(redisTemplate.opsForValue().get(principal.getUsername()))) {
                        token = jwt.generateToken(map);
                        Date expiration = jwt.parseToken(token).getExpiration();
                        redisTemplate.opsForValue().set(principal.getUsername(),token);
                        redisTemplate.expireAt(principal.getUsername(),expiration);

                    }

                    httpServletResponse.setStatus(HttpStatus.OK.value());
                    httpServletResponse.setContentType("application/json; charset=UTF-8");
                    PrintWriter writer = httpServletResponse.getWriter();
                    httpServletResponse.setHeader("token", (String) redisTemplate.opsForValue().get(principal.getUsername()));
                    CommonsResult success = commonsResult.success("登陆成功！");
                    writer.write(JSONObject.toJSONString(success));
                    writer.close();
                    writer.flush();
                })
                // 登录失败
                .failureHandler((httpServletRequest, httpServletResponse, e) -> {
                    httpServletResponse.setStatus(HttpStatus.OK.value());
                    httpServletResponse.setContentType("application/json; charset=UTF-8");
                    PrintWriter writer = httpServletResponse.getWriter();
                    CommonsResult success = null;
                    if (e instanceof UsernameNotFoundException){
                        success = commonsResult.failed(e.getMessage());
                    }
                    else if (e instanceof BadCredentialsException){
                        success = commonsResult.failed("用户名或密码错误！");
                    }
                    else if (e instanceof DisabledException){
                        success = commonsResult.failed("用户被禁用！");
                    }
                    else {
                        success = commonsResult.failed("登录失败！详情："+e.getMessage());
                    }
                    writer.write(JSONObject.toJSONString(success));
                    writer.close();
                    writer.flush();
                }).permitAll()
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                // 注销成功
                .logout()
                .logoutSuccessUrl("/logout")
                .logoutSuccessHandler((request, response, authentication) -> {
                    CommonsResult success = commonsResult.success(authentication);
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter out = response.getWriter();
                    out.write(JSONObject.toJSONString(success));
                    out.flush();
                    out.close();
                })
                .permitAll()
                .and()
                // 未登录请求资源
                .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint())
                .and()
                .authorizeRequests();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService);
    }

}
